package net._708s.logmanager.service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.map.ObjectMapper;

import net._708s.logmanager.domain.Log;
import net._708s.logmanager.domain.common.JsonObject;
import net._708s.logmanager.domain.common.PageInfo;
import net._708s.logmanager.util.MyParam;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

/**
 * 
 * @author  ajian
 */
public class SearchService {
	public JsonObject search(String keyword, Integer page, Integer pageSize,
			String index, String[] types, String[] sources, Long range)
			{
		JsonObject json = new JsonObject();

		if (null == page || page < 1) {
			page = 1;
		}

		if (pageSize == null || pageSize < 1 || pageSize > 100) {
			pageSize = PageInfo.DEFAULT_PAGE_SIZE;
		}

		IndexReader reader = null;
		try {

			BooleanQuery booleanQuery = new BooleanQuery();

			reader = DirectoryReader.open(FSDirectory.open(new File(index)));
			IndexSearcher searcher = new IndexSearcher(reader);
			Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
			// set q
			Query keywordquery = new QueryParser(Version.LUCENE_40, "message",
					analyzer).parse(keyword);
			booleanQuery.add(keywordquery, Occur.MUST);
			// set fq

			// set source filter
			if (sources != null) {
				BooleanQuery booleanQuery1 = new BooleanQuery();
				for (int i = 0; i < sources.length; i++) {
					TermQuery sourceTermQuery = new TermQuery(new Term("source",
							sources[i]));
					booleanQuery1.add(sourceTermQuery, Occur.SHOULD);
				}
				
				booleanQuery.add(booleanQuery1, Occur.MUST);
			}
			// set type filter
			if (types != null) {
				BooleanQuery booleanQuery2 = new BooleanQuery();
				for (int i = 0; i < types.length; i++) {
					TermQuery sourceTermQuery = new TermQuery(new Term("type",
							types[i]));
					booleanQuery2.add(sourceTermQuery, Occur.SHOULD);
				}
				
				booleanQuery.add(booleanQuery2, Occur.MUST);
			}
			Map<String,Object> result = null;
			// set range
			if (range != null) {
				NumericRangeFilter<?> dateFilter = NumericRangeFilter
						.newLongRange("date", (new Date().getTime() - range),
								new Date().getTime(), true, true);
				result = doPagingSearch(searcher, booleanQuery, page, pageSize,
						dateFilter);
			} else {
				result = doPagingSearch(searcher, booleanQuery, page, pageSize,
						null);
			}
			int count = (Integer) result.get("count");
			if (count == 0) {
				json.setMessage("Not Found Data!");
			} else {
				/*-------------------------pageInfo-------------------------*/
				long totalNumber = count;
				long totalPage = totalNumber % pageSize == 0 ? totalNumber
						/ pageSize : totalNumber / pageSize + 1;

				PageInfo pageInfo = new PageInfo();
				pageInfo.setPage(page);
				pageInfo.setPageSize(pageSize);
				pageInfo.setMaxPage(((Long) totalPage).intValue());
				pageInfo.setTotal(((Long) totalNumber).intValue());

				json.setPage(pageInfo);
				json.setData(result);
				json.setStatus(JsonObject.STATUS_SUCCESS);
			}

		} catch (Exception e) {
			e.printStackTrace();
			json.setMessage(e.getMessage());
			json.setStatus(JsonObject.STATUS_FAIL);
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		/*--------------设置返回的数据范围--------------*/

		return json;
	}
	
	public String searchOfJson(String keyword, Integer page, Integer pageSize,
			String index, String[] types, String[] sources, Long range)
			{
		JsonObject jsonObject = search(keyword,page,pageSize,index, types, sources, range);
		ObjectMapper objectMapper = new ObjectMapper();
		String result="";
		try {
			result = objectMapper.writeValueAsString(jsonObject);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	/** Simple command-line based search demo. */
	public static void main(String[] args) throws Exception {
		SearchService searchService = new SearchService();
		String path = Thread.currentThread().getContextClassLoader()
				.getResource("").getPath();
		MyParam mySystemParameter = MyParam.getInstance(path
				+ "/application.properties");
		String result = searchService.searchOfJson("log", 1, 10,
				mySystemParameter.getPropertie("index.url"),
				new String[] { "info","error" }, null,
				new Date().getTime() - 1404187200000l);
		System.out.println(result);
		System.out.println("end!");
	}

	/**
   * 
   */
	public static Map<String,Object> doPagingSearch(IndexSearcher searcher, Query query,
			int currentPage, int pageSize, Filter filter) throws IOException {
		Map<String,Object> result_map = new HashMap<String,Object>();
		List<Log> logList = new ArrayList<Log>();
		TopDocs topDocs = null;
		if (filter != null) {
			topDocs = searcher.search(query, filter, currentPage * pageSize);
		} else {
			topDocs = searcher.search(query, currentPage * pageSize);
		}

		int endNuM = Math.min(topDocs.totalHits, currentPage * pageSize);
		if ((currentPage - 1) * pageSize < endNuM) {

			for (int i = (currentPage - 1) * pageSize; i < endNuM; i++) {
				ScoreDoc temp = topDocs.scoreDocs[i];
				// 通过编号去查找相应的document
				Document doc = searcher.doc(temp.doc);
				String id = doc.get("id");
				String source = doc.get("source");
				String type = doc.get("type");
				String message = doc.get("message");
				Long date = Long.valueOf(doc.get("date"));

				Log log = new Log();
				log.setId(id);
				log.setMessage(message);
				log.setSource(source);
				log.setType(type);
				log.setDate(new Date(date));
				logList.add(log);
			}
		}
		result_map.put("count", topDocs.totalHits);
		result_map.put("itemList", logList);
		return result_map;
	}
}
